<?php
namespace App\Common\Cla\ClaBase\Traits\LinkedTree;

use App\Common as com;

trait StaticFun {

	/**
	 * @var string
	 */
	// protected static string $tableModelDataUnitClass; // 名DataUnitlass

	/**
	 * @var string
	 */
	// protected static string $mainFieldName = 'id'; // 本级字段名

	/**
	 * @var string
	 */
	// protected static string $parentFieldName = 'parent_id'; // 上级字段名

	/**
	 * 检测新的上级是否会形成死循环
	 * @param int $currentId 当前树id
	 * @param int $newParentId 新的上级系统分类id
	 * @return bool [false]没有循环 [true]出现死循环
	 * @throws
	 */
	public static function checkRepeatOfNewUp( int $currentId, int $newParentId ):bool {
		if( $currentId == $newParentId ) return true;
		//
		$parentIdLists = self::getUpReLevelMap( $newParentId );
		foreach ( $parentIdLists as $parentId ){
			if( $parentId == $currentId ) return true;
		}
		return false;
	}

	/**
	 * 获取当前树的所有上级集合(按等级分组)
	 * @param int $currentId 当前树id
	 * @param int $layerNum 获取的层数（默认：99999）
	 * @return array 返回包含上级树id的层级数组（格式为：array( {层数} => {上级分类id}, 1 => 2 )），层数为0是自身，大于0为上级层数
	 * @todo :o 待优化，要使用数据库存储过程获取
	 * @throws
	 */
	public static function getUpReLevelMap( int $currentId, int $layerNum = 99999 ):array {
		//初始化数组
		$parentData = [];//保存上级数据
		$checkRepeatParent = [ $currentId => 1 ];//检测是否有重复的上级，防止死循环
		$upClassId = $parentData[0] = $currentId;
		//循环获取多层上级
		for ( $layerI = 1; $layerI <= $layerNum; $layerI++ ) {
			$upClassId = self::getUpId( $upClassId );
			if( $upClassId == 0 ) break;
			if( ( $checkRepeatParent[ $upClassId ] ?? 0 ) == 1 ){
				throw com\Lib\Err\Exception::makeOfNew( '上级重复，出现死循环', com\Lib\Err\Code::$sysAssertError );
			}
			$checkRepeatParent[ $upClassId ] = 1;//记录
			$parentData[ $layerI ] = $upClassId;
		}
		//返回
		return $parentData;
	}

	/**
	 * 获取树的上一层树id
	 * @param int $currentId 要获取指定分类的上层树id
	 * @return int 返回上级树id，没有则返回0。
	 */
	public static function getUpId( int $currentId ):int {
		$dataUnit = self::newDataUnit();
		$data = $dataUnit->where( self::$mainFieldName, $currentId )->value( self::$parentFieldName, 0 );
		return $data;
	}

	/**
	 * 取当前表模型
	 * @return com\Model\Base\DataUnit
	 */
	public static function newDataUnit():com\Model\Base\DataUnit {
		/** @var com\Model\Base\DataUnit $dataUnit */
		return new self::$tableModelDataUnitClass;
	}

	/**
	 * 获取下级id（单级）
	 * @param string $currentId 要获取指定树的上级会员id
	 * @return array 返回下级包含id的数组（如:[1,2,3... ]），没有上级则返回空数组。
	 */
	public static function getDownIds( $currentId ){
		//格式化参数
		$currentId = (int)$currentId;
		//检查参数
		if(empty($currentId) || $currentId=='0') return array();//不存在分销商，直接返回
		//获取所有下级->查询
		$tableModel = self::newDataUnit();
		$sontreeListsData = $tableModel->fieldAndReset( [ self::$mainFieldName ] )->where( self::$parentFieldName, $currentId )->select()->toArray();
		//生成返回结果
		$downSontreeArray = array();
		foreach ( $sontreeListsData as $sontree_value ){
			$downSontreeArray[] = (int)$sontree_value[ self::$mainFieldName ];
		}
		//返回
		return $downSontreeArray;
	}

	/**
	 * 获取下级id（多级）(以地图的形式返回)
	 * @param int $currentId 当前树id
	 * @param int $levelNum 获取的最大级别[默认：888]
	 * @param array $_hasSonArray 方法内部使用，不需要用户传入参数
	 * @return array array( array(), array(),... ) (层数从近到远)
	 */
	public static function getAllDownIdsReMap( $currentId, $levelNum = 888, array &$_hasSonArray = null ){
		if( $levelNum <= 0 ) return array();
		// 初始化数组
		$downSonMap = array(); // 下级地图
		if( ! is_array( $_hasSonArray ) ) $_hasSonArray = array( $currentId => 1 ); //初始化下级重复检查数组，检测是否有重复的下级，防止死循环
		// 循环获取多级分销商
		$downSontreeArray = self::getDownIds( $currentId );
		foreach ( $downSontreeArray as $downSonId ){
			if( ( $_hasSonArray[ $downSonId ] ?? 0 ) == 1 ) continue;
			$_hasSonArray[ $downSonId ] = 1;
			$downSonSonMap = self::getAllDownIdsReMap( $downSonId, $levelNum - 1, $_hasSonArray );
			if( empty( $downSonSonMap ) ){
				$downSonMap[ $downSonId ] = $downSonId;
			}else{
				$downSonMap[ $downSonId ] = $downSonSonMap;
			}
		}
		//返回
		return $downSonMap;
	}

	/**
	 * 获取下级id（多级）
	 * @param int $currentId 当前树id
	 * @param int $levelNum 获取的最大级别[默认：888]
	 * @return int[] [ 1, 2, 3, ... ]
	 */
	public static function getAllDownIds( $currentId, $levelNum = 888 ){
		//返回
		return com\Lib\Fun\Array_::multiToOneArray( self::getAllDownIdsReMap( $currentId, $levelNum ) );
	}


	/**
	 * 是否为上级，并返回上级级别[最大支持999级]
	 * @param int $currentId 当前树id
	 * @param int $upId 要判断的上级id
	 * @return bool
	 */
	public function isUp( int $currentId, int $upId ):bool {
		return $this->isUpReLevel( $currentId, $upId  ) > 0;
	}


	/**
	 * 是否为上级，并返回上级级别[最大支持999级]
	 * @param int $currentId 当前树id
	 * @param int $upId 要判断的上级id
	 * @return int 返回上级级别1、2、3、...，不是上级返回0。
	 */
	public static function isUpReLevel( int $currentId, int $upId ){
		$fatherId = $currentId;
		for( $i = 1; $i <= 999; $i++ ){
			$fatherId = self::getUpId( $fatherId );
			if( $fatherId <= 0 ) return 0;
			if( $upId == $fatherId ) return $i;
		}
		return 0;
	}

	/**
	 * 是否为下级，并返回下级级别[最大支持999级]
	 * @param int $currentId 当前树id
	 * @param int $sonId 要判断的下级id
	 * @return int 返回下级级别1、2、3、...，不是下级返回0。
	 */
	public function isDown( int $currentId, int $sonId ):bool {
		return $this->isDownReLevel( $currentId, $sonId  ) > 0;
	}

	/**
	 * 是否为下级，并返回下级级别[最大支持999级]
	 * @param int $currentId 当前树id
	 * @param int $sonId 要判断的下级id
	 * @return int 返回下级级别1、2、3、...，不是下级返回0。
	 */
	public static function isDownReLevel( int $currentId, int $sonId ):int {
		$fatherId = $sonId;
		for( $i = 1; $i <= 999; $i++ ){
			$tableModel = self::newDataUnit();
			$reSontreeTmp = $tableModel->fieldAndReset( [ self::$parentFieldName ] )->where( self::$mainFieldName, $fatherId )->findOrNullToArray();
			$fatherId = $reSontreeTmp[ self::$parentFieldName ] ?? 0;
			//
			if( $fatherId === 0 ) return 0;
			if( $currentId == $fatherId ) return $i;
		}
		return 0;
	}

}
